#include <x86emu/x86emu.h>

#include <eku/stdlib.h>
#include <eku/system.h>

#include <inc/mmu.h>
#include <inc/layout.h>

x86emu_t *emu;
char *rm_image;

static void
flush_log(x86emu_t *emu, char *buf, unsigned size)
{
	 char x = buf[size];
	 buf[size] = 0;
	 printf("%s", buf);
	 buf[size] = x;
}

static int
module_load(void)
{
	 rm_image = (char *)vmalloc(RM_IMAGE_PAGES << PAGE_SHIFT, sysconf.rm_image_phys);
	 
	 emu = x86emu_new(X86EMU_PERM_VALID | X86EMU_PERM_RWX, X86EMU_PERM_RW);
	 int i;
	 for (i = 0; i != (RM_IMAGE_PAGES << PAGE_SHIFT) >> X86EMU_PAGE_BITS; ++ i)
	 {
	 	  uint32_t addr = i << X86EMU_PAGE_BITS;
		  /* int j; */
		  /* for (j = 0; j != 1 << X86EMU_PAGE_BITS; ++ j) */
		  /* { */
		  /* 	   x86emu_write_byte_noperm(emu, addr + j, *(rm_image + addr + j)); */
		  /* } */
		  x86emu_set_page(emu, addr, rm_image + addr);
	 }
	 x86emu_set_perm(emu, 0, RM_IMAGE_PAGES << PAGE_SHIFT, X86EMU_PERM_VALID | X86EMU_PERM_RWX);

	 emu->x86.R_AX = 0x4F00;
	 emu->x86.R_DI = 0x7f00;
	 x86emu_set_seg_register(emu, emu->x86.R_ES_SEL, 0x0000);

	 emu->x86.R_IP = 0x7c00;
	 emu->x86.R_SP = 0x7c00;
	 x86emu_set_seg_register(emu, emu->x86.R_CS_SEL, 0x0000);
	 x86emu_set_seg_register(emu, emu->x86.R_SS_SEL, 0x0000);
	 for (i = 0x7c00; i != 0x7f00; ++ i)
	 {
	 	  x86emu_write_byte(emu, i, 0x90);
	 }

	 x86emu_set_perm(emu, 0x7f00, 0x8000, X86EMU_PERM_VALID | X86EMU_PERM_RW);

	 /* emu->log.trace |= X86EMU_TRACE_CODE; */
	 /* emu->log.trace |= X86EMU_TRACE_REGS; */
	 
	 x86emu_set_log(emu, 2000000, flush_log);
	 x86emu_intr_raise(emu, 0x10, INTR_TYPE_SOFT, 0);
	 x86emu_run(emu, X86EMU_RUN_NO_CODE | X86EMU_RUN_LOOP);
	 x86emu_clear_log(emu, 1);
	 
	 for (i = 0; i != 256; ++ i)
	 {
		  unsigned char c = (unsigned char)x86emu_read_byte_noperm(emu, 0x7f00 + i);
		  printf("%02x(%c)", c, c);
	 	  if (i % 10 == 9) printf("\n");
	 	  else printf(" ");
	 }
	 if (i % 10 != 0) printf("\n");

	 printf("ax: %04x\n", emu->x86.R_AX);
	 

	 return 0;
}

static int
module_unload(void)
{
	 return 0;
}
